"""
InCloud MCP 服务器安全控制模块
用于控制 API 访问权限，防止误操作高危接口
"""

import re
import logging
from typing import Dict, List, Set, Optional, Tuple
from enum import Enum

logger = logging.getLogger(__name__)

class SecurityLevel(Enum):
    """安全级别枚举"""
    SAFE = "safe"           # 安全操作（查询、列表等）
    MODERATE = "moderate"   # 中等风险操作（创建、更新等）
    HIGH_RISK = "high_risk" # 高风险操作（删除、重启等）
    FORBIDDEN = "forbidden" # 禁止操作

class SecurityPolicy:
    """安全策略配置"""
    
    def __init__(self):
        # 高危操作关键词（方法名、路径、操作类型）
        self.high_risk_keywords = {
            # 删除操作
            'delete', 'remove', 'destroy', 'terminate', 'drop',
            # 重启/停止操作  
            'restart', 'reboot', 'stop', 'shutdown', 'halt',
            # 重置操作
            'reset', 'format', 'wipe', 'clear',
            # 强制操作
            'force', 'kill',
            # 批量操作
            'batch', 'bulk', 'mass',
        }
        
        # 安全操作关键词
        self.safe_keywords = {
            'get', 'list', 'describe', 'show', 'view', 'query', 
            'search', 'find', 'check', 'status', 'info', 'detail'
        }
        
        # 中等风险操作关键词
        self.moderate_keywords = {
            'create', 'add', 'new', 'update', 'modify', 'edit', 
            'change', 'set', 'configure', 'start', 'enable'
        }
        
        # 路径模式黑名单（正则表达式）
        self.path_blacklist_patterns = [
            r'.*/delete.*',           # 包含 delete 的路径
            r'.*/remove.*',           # 包含 remove 的路径
            r'.*/destroy.*',          # 包含 destroy 的路径
            r'.*/force.*',            # 包含 force 的路径
            r'.*/batch.*delete.*',    # 批量删除
            r'.*/bulk.*delete.*',     # 批量删除
        ]
        
        # 方法黑名单
        self.method_blacklist = {
            # 一般来说 DELETE 方法都是高危的
            # 但可以根据具体情况调整
        }
        
        # 服务特定的安全规则
        self.service_specific_rules = {
            'icompute': {
                'high_risk_paths': [
                    r'.*/vhosts/.*/delete',
                    r'.*/vms/.*/delete', 
                    r'.*/vhosts/.*/restart',
                    r'.*/vms/.*/restart',
                    r'.*/vhosts/.*/stop',
                    r'.*/vms/.*/stop',
                ],
                'forbidden_paths': [
                    r'.*/vhosts/.*/force.*',
                    r'.*/vms/.*/force.*',
                ]
            },
            'istorage': {
                'high_risk_paths': [
                    r'.*/virtualVolume/.*/delete',
                    r'.*/volume/.*/delete',
                    r'.*/storage/.*/format',
                ],
                'forbidden_paths': [
                    r'.*/volume/.*/destroy',
                    r'.*/storage/.*/wipe',
                ]
            },
            'inetwork': {
                'high_risk_paths': [
                    r'.*/network/.*/delete',
                    r'.*/subnet/.*/delete',
                ],
                'forbidden_paths': []
            }
        }

class SecurityController:
    """安全控制器"""
    
    def __init__(self, policy: Optional[SecurityPolicy] = None):
        self.policy = policy or SecurityPolicy()
        self.enabled = True
        
        # 用户自定义的白名单和黑名单
        self.user_whitelist: Set[str] = set()  # 明确允许的 API
        self.user_blacklist: Set[str] = set()  # 明确禁止的 API
        
        logger.info("Security controller initialized")
    
    def set_enabled(self, enabled: bool):
        """启用或禁用安全控制"""
        self.enabled = enabled
        logger.info(f"Security control {'enabled' if enabled else 'disabled'}")
    
    def add_to_whitelist(self, api_patterns: List[str]):
        """添加到白名单"""
        for pattern in api_patterns:
            self.user_whitelist.add(pattern.lower())
        logger.info(f"Added {len(api_patterns)} patterns to whitelist")
    
    def add_to_blacklist(self, api_patterns: List[str]):
        """添加到黑名单"""
        for pattern in api_patterns:
            self.user_blacklist.add(pattern.lower())
        logger.info(f"Added {len(api_patterns)} patterns to blacklist")
    
    def evaluate_api_security(self, service: str, method: str, path: str,
                            operation_id: Optional[str] = None,
                            config_security=None) -> Tuple[SecurityLevel, str]:
        """
        评估 API 的安全级别

        Args:
            service: 服务名称
            method: HTTP 方法
            path: API 路径
            operation_id: 操作 ID（可选）
            config_security: 配置文件中的安全设置

        Returns:
            (安全级别, 评估原因)
        """
        if not self.enabled:
            return SecurityLevel.SAFE, "Security control disabled"

        method_upper = method.upper()
        api_signature = f"{method_upper} {path}".lower()
        path_lower = path.lower()

        # 1. 检查配置文件中的路径白名单（优先级最高）
        if config_security and hasattr(config_security, 'path_whitelist'):
            for whitelist_pattern in config_security.path_whitelist:
                if re.search(whitelist_pattern.lower(), path_lower):
                    return SecurityLevel.SAFE, f"Matched config path whitelist: {whitelist_pattern}"

        # 2. 检查用户白名单
        for whitelist_pattern in self.user_whitelist:
            if re.search(whitelist_pattern, api_signature):
                return SecurityLevel.SAFE, f"Matched user whitelist pattern: {whitelist_pattern}"

        # 3. 检查配置文件中的路径黑名单
        if config_security and hasattr(config_security, 'path_blacklist'):
            for blacklist_pattern in config_security.path_blacklist:
                if re.search(blacklist_pattern.lower(), path_lower):
                    return SecurityLevel.FORBIDDEN, f"Matched config path blacklist: {blacklist_pattern}"

        # 4. 检查用户黑名单
        for blacklist_pattern in self.user_blacklist:
            if re.search(blacklist_pattern, api_signature):
                return SecurityLevel.FORBIDDEN, f"Matched user blacklist pattern: {blacklist_pattern}"

        # 5. 检查基于 HTTP 方法的策略（新增）
        if config_security and hasattr(config_security, 'method_policies'):
            method_policy = config_security.method_policies.get(method_upper)
            if method_policy:
                # 检查方法特定的禁止模式
                for forbidden_pattern in method_policy.forbidden_patterns:
                    if re.search(forbidden_pattern.lower(), path_lower):
                        return SecurityLevel.FORBIDDEN, f"Matched {method_upper} forbidden pattern: {forbidden_pattern}"

                # 检查方法特定的安全模式
                for safe_pattern in method_policy.safe_patterns:
                    if re.search(safe_pattern.lower(), path_lower):
                        return SecurityLevel.SAFE, f"Matched {method_upper} safe pattern: {safe_pattern}"

                # 检查方法特定的高风险模式
                for high_risk_pattern in method_policy.high_risk_patterns:
                    if re.search(high_risk_pattern.lower(), path_lower):
                        return SecurityLevel.HIGH_RISK, f"Matched {method_upper} high-risk pattern: {high_risk_pattern}"

                # 使用方法的默认级别
                default_level = method_policy.default_level.lower()
                if default_level == "safe":
                    return SecurityLevel.SAFE, f"{method_upper} method default level: safe"
                elif default_level == "moderate":
                    return SecurityLevel.MODERATE, f"{method_upper} method default level: moderate"
                elif default_level == "high_risk":
                    return SecurityLevel.HIGH_RISK, f"{method_upper} method default level: high_risk"

        # 6. 检查服务特定策略（新增）
        if config_security and hasattr(config_security, 'service_policies'):
            service_policy = config_security.service_policies.get(service.lower())
            if service_policy:
                # 检查资源特定规则
                resource_type = self._extract_resource_type(path)
                if resource_type:
                    resource_config = getattr(service_policy, resource_type, None)
                    if resource_config:
                        # 检查删除操作
                        if method_upper == 'DELETE' and not resource_config.allow_delete:
                            return SecurityLevel.FORBIDDEN, f"Delete operations forbidden for {resource_type} in {service}"

                        # 检查重启操作
                        if 'restart' in path_lower and not resource_config.allow_restart:
                            return SecurityLevel.FORBIDDEN, f"Restart operations forbidden for {resource_type} in {service}"

                        # 检查停止操作
                        if 'stop' in path_lower and not resource_config.allow_stop:
                            return SecurityLevel.FORBIDDEN, f"Stop operations forbidden for {resource_type} in {service}"

        # 7. 检查传统的服务特定规则（保持向后兼容）
        if service.lower() in self.policy.service_specific_rules:
            service_rules = self.policy.service_specific_rules[service.lower()]

            # 检查禁止路径
            for forbidden_pattern in service_rules.get('forbidden_paths', []):
                if re.search(forbidden_pattern, path_lower):
                    return SecurityLevel.FORBIDDEN, f"Matched service forbidden pattern: {forbidden_pattern}"

            # 检查高风险路径
            for high_risk_pattern in service_rules.get('high_risk_paths', []):
                if re.search(high_risk_pattern, path_lower):
                    return SecurityLevel.HIGH_RISK, f"Matched service high-risk pattern: {high_risk_pattern}"

        # 8. 检查通用黑名单模式
        for blacklist_pattern in self.policy.path_blacklist_patterns:
            if re.search(blacklist_pattern, path_lower):
                return SecurityLevel.HIGH_RISK, f"Matched general blacklist pattern: {blacklist_pattern}"

        # 9. 基于关键词分析
        text_to_analyze = f"{method} {path} {operation_id or ''}".lower()

        # 检查高危关键词
        for keyword in self.policy.high_risk_keywords:
            if keyword in text_to_analyze:
                return SecurityLevel.HIGH_RISK, f"Contains high-risk keyword: {keyword}"

        # 检查中等风险关键词
        for keyword in self.policy.moderate_keywords:
            if keyword in text_to_analyze:
                return SecurityLevel.MODERATE, f"Contains moderate-risk keyword: {keyword}"

        # 检查安全关键词
        for keyword in self.policy.safe_keywords:
            if keyword in text_to_analyze:
                return SecurityLevel.SAFE, f"Contains safe keyword: {keyword}"

        # 10. 基于 HTTP 方法的默认评估
        if method_upper == 'DELETE':
            return SecurityLevel.HIGH_RISK, "DELETE method is high-risk by default"
        elif method_upper in ['POST', 'PUT', 'PATCH']:
            return SecurityLevel.MODERATE, f"{method_upper} method has moderate risk"
        elif method_upper in ['GET', 'HEAD', 'OPTIONS']:
            return SecurityLevel.SAFE, f"{method_upper} method is generally safe"

        # 默认为中等风险
        return SecurityLevel.MODERATE, "Default moderate risk level"

    def _extract_resource_type(self, path: str) -> Optional[str]:
        """从路径中提取资源类型"""
        path_lower = path.lower()
        if 'vhost' in path_lower:
            return 'vhosts'
        elif 'vm' in path_lower:
            return 'vms'
        elif 'volume' in path_lower:
            return 'volumes'
        return None
    
    def is_api_allowed(self, service: str, method: str, path: str,
                      operation_id: Optional[str] = None,
                      require_confirmation: bool = False,
                      config_security=None) -> Tuple[bool, str, SecurityLevel]:
        """
        检查 API 是否被允许执行

        Args:
            service: 服务名称
            method: HTTP 方法
            path: API 路径
            operation_id: 操作 ID
            require_confirmation: 是否需要用户确认
            config_security: 配置文件中的安全设置

        Returns:
            (是否允许, 原因, 安全级别)
        """
        security_level, reason = self.evaluate_api_security(
            service, method, path, operation_id, config_security
        )

        if security_level == SecurityLevel.FORBIDDEN:
            return False, f"API is forbidden: {reason}", security_level

        if security_level == SecurityLevel.HIGH_RISK and not require_confirmation:
            return False, f"High-risk API requires explicit confirmation: {reason}", security_level

        return True, f"API allowed: {reason}", security_level

# 全局安全控制器实例
security_controller = SecurityController()

def get_security_controller() -> SecurityController:
    """获取全局安全控制器实例"""
    return security_controller
